<?php
/** Used by Rho_DB, no need to manually include this file.
*
* @see Rho_DB::factory()
* @package Rho
* @subpackage Rho-database */

/** Load the interface definition.*/
require_once Rho::$PATH.'rho/db/Rho_DB_Driver.inc.php';

/** mySQL driver.
* Do NOT use this class directly - use DB::factory() .
*
* Uses the mysqli (mySQL Improved) extension.
*
* @see DB::factory()
* @package Rho
* @subpackage Rho-database */
class DB_mysqli_Driver implements Rho_DB_Driver{

  private $_link;
  private $_name;

  /** @ignore */
  public function __construct(& $name){
    $this->_name='db.'.$name;
  }
  
  public function connect(){
    $this->_connect();
  }  
  
  private function _connect(){
    if(isset($this->_link) ){
      return $this->_link; # already set so return
    }
    // get server name
    $server=Rho::conf($this->_name.'.server', 'localhost');
    if(Rho::conf($this->_name.'.use_perm') ){
      $server='p:'.$server; # permanent connection
    }
    // connect
    $this->_link=new mysqli($server, Rho::conf($this->_name.'.username'), Rho::conf($this->_name.'.password'), Rho::conf($this->_name.'.dbname'),  Rho::conf($this->_name.'.port', 10061), Rho::conf($this->_name.'.socket', 'mysql') );
    // check for error
    if(mysqli_connect_error() ){
      $e=new DB_Connection_Exception("DB ".$this->_name." Could not connect to $server: ".mysqli_connect_error(), mysqli_connect_errno() );
      $this->_link=FALSE;
      throw $e;
      return FALSE;
    }
    // set encoding
    /* Note that mysql uses a different encoding naming convention
    * e.g. utf8 instead of UTF-8 */
    if(! $this->_link->set_charset(Rho::conf($this->_name.'.enc', 'utf8')) ){
      Rho_Log::error(7100, 'DB mysqli could not change client charset: '.$this->_link->error);
    }
    return $this->_link;
  }
  
  public function query(& $sql){
    if(! $this->_connect() ) return FALSE;
    $result=$this->_link->query($sql);
    if(! $result){
      throw $this->getException('query failed');
      return FALSE;
    }
    return $result;
  }
  
  public function affectedRows(& $resource){
    if(! $this->_connect() ) return FALSE;
    $result=$this->_link->affected_rows();
    if($result==-1){
      throw $this->getException('affectedRows returned false');
      return FALSE;
    }
    return $result;
  }
  
  public function freeResult(& $resource){
    $resource->free();
    return TRUE;
  }
  
  public function numRows(& $resource){
    return $resource->num_rows();
  }
  
  private function getException($cause='Unknown'){
    if(isset($this->_link) && $this->_link!=FALSE){
      return new Rho_Exception('DB error: '.$this->_link->error(), 7000+$this->_link->errno() );
    }
    return new Rho_Exception('DB error: '.$cause, 7000);
  }
  
  public function fetchObject(& $resource, & $record_class, & $model){
    return $resource->fetch_object($record_class, array($model) );
  }
  
  public function seek(& $resource, $row_number){
    $result=$resource->data_seek($row_number);
    if(! $result){
      throw $this->getException('seek returned false');
      return FALSE;
    }
    return TRUE;
  }
  
  public function & getLink(){
    if(isset($this->_link) ){
      return $this->_link;
    }
    return NULL;
  }
  
  public function lastInsertID(& $resource){
    if(! $this->_connect() ) return FALSE;
    $result=$this->_link->insert_id($this->_link);
    if(! $result){
      throw $this->getException('lastInsertID returned 0');
      return 0;
    }
    return $result;
  }
  
  public function cleanString(& $str){
    stripslashes($str);    
  }
  
  public function convertDate(& $date){
    return;
  }
  
  public function convertTime(& $time){
    return;
  }
  
  public function convertDateTime(& $date){
    return;
  }
  
  public function escapeField(& $field, & $table){
    if(empty($table) ) return $field=='*' ? '*' : "`$field`" ;
    return $field=='*' ? $this->escapeTable($table).'*' : $this->escapeTable($table)."`$field`" ;
  }
  
  public function escapeTable(& $table){
    return "`$table`";
  }
  
  public function escapeString(& $str){
    if($str==NULL) return 'NULL';
    if(! $this->_connect() ){ // we need an active link 
      throw $this->getException('Need conncetion to escapeString()');
      return "''";
    }
    return "'".$this->_link->real_escape_string ($str)."'";
  }
  
  public function escapeDate(& $date){
    if($date==NULL) return 'NULL';
    return "'".$date."'";
  }
  
  public function escapeTime(& $time){
    if($time==NULL) return 'NULL';
    return "'".$time."'";
  }
  
  public function escapeDateTime(& $date){
    if($date==NULL) return 'NULL';
    return "'".$date."'";
  }
  
  public function limit($qty, $offset=NULL){
    return $offset==NULL ? "LIMIT $qty" : 'LIMIT  $offset,$qty';
  }
  
  public function close(){
    if(isset($this->_link) && $this->_link!=FALSE){
      $this->_link->close();
      unset($this->_link);
    }
  }
  
  /** @ignore */
  function __destruct(){
    @$this->close();
  }
}